﻿module xenocide;

public import tango.util.log.Log;
public import tango.util.log.AppendConsole;

import tango.core.Thread;
import tango.time.Clock;
public import tango.io.Stdout;

public import tango.stdc.stringz;
public import tango.stdc.string;
public import derelict.sdl.sdl;
public import derelict.sdl.image;
public import derelict.opengl.gl;
public import derelict.opengl.glu;
public import tango.text.convert.Layout;

public import xenGameState;
public import xenWindow;
public import xenObjects;

public import blaze.all;

class XenApp
{
    char[] name="Xenocide";
	// horizontal and vertical screen resolution
	const int   xResolution     = 800;
	const int   yResolution     = 600;
	const int[2] size=[800,600];
	// number of bits per pixel used for display. 24 => true color
	const int   bitsPerPixel    = 24;
	
	// field of view => the angle our camera will see vertically
	const float fov             = 90.f;
	
	// distance of the near clipping plane
	const float nearPlane       = .1f;
	
	// distance of the far clipping plane
	const float farPlane        = 100.f;
	
	GameState currentGS;
	
	
	bool shift,ctrl,alt;
	
	Logger logger;
	Layout!(char) L;

    /*
    # Box2D-callbacks
    destructionListener = None
    boundaryListener = None
    contactListener = None
    debugDraw = None

    # Window-related
    fontname = "saved_by_zero"
    fontsize = 10
    font = None
    textGroup = None
    keys=pyglet.window.key.KeyStateHandler()
    */
    this(Logger iLogger)
	{
		logger=iLogger;
		L = new Layout!(char)();

		
		initGL();
		
		currentGS=new xenGS(logger,"Test","Test",this);
		

		
		/*config=Config(stencil_size=8)
    
        //super(Main, self).__init__(config=config,height=800,width=1024, resizable=True)
        
        //screenSize =(width, height)
        # Initialize the text display group
        //textGroup = grText(self)

        # Load the font and record the screen dimensions
        font = pyglet.font.load(fontname, fontsize)
        
        pyglet.resource.path=['','res']
        pyglet.resource.reindex()
        pyglet.resource.add_font('saved_by_zero.ttf')
        
        gsStack=[]

        settings=xenSettings()

        currentGameState=MainMenu("menu","XENOCIDE","Saved By Zero")
        currentGameState.activate()
	*/
	}
	void initGL()
	{
		
		        // initialize SDL, GL and GLU Derelict modules
		DerelictSDL.load();
		DerelictGL.load();
		DerelictSDLImage.load();
		DerelictGLU.load();
			
		
		
		// initialize SDL's VIDEO module
		SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
	
		// enable double-buffering
		SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
		SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 1 );
		
		// create our OpenGL window
		SDL_SetVideoMode(xResolution, yResolution, bitsPerPixel, SDL_OPENGL);
		SDL_WM_SetCaption(toStringz(name), null);
	
		DerelictGL.loadExtensions();


		//setupGL(xResolution, yResolution);
	}
	// be nice and release all resources
	void cleanup() {
		// tell SDL to quit
		SDL_Quit();
	
		// release GL, GLU and SDL's shared libs
		DerelictGLU.unload();
		DerelictGL.unload();
		DerelictSDL.unload();
	}
	void setupGL(int xResolution, int yResolution)
	{
		
		// number of bits per pixel used for display. 24 => true color
		const int   bitsPerPixel    = 24;

		// field of view => the angle our camera will see vertically
		const float fov             = 90.f;

		// distance of the near clipping plane
		const float nearPlane       = .1f;

		// distance of the far clipping plane
		const float farPlane        = 100.f;




	    // switch to the projection mode matrix
	    glMatrixMode(GL_PROJECTION);

	    // load the identity matrix for projection
	    glLoadIdentity();

	    // setup a perspective projection matrix
	    gluPerspective(fov, cast(float)xResolution / yResolution, nearPlane, farPlane);

	    // switch back to the modelview transformation matrix
	    glMatrixMode(GL_MODELVIEW);

	    // load the identity matrix for modelview
	    glLoadIdentity();
	}
	
	
	void run()
	{
		
		SDL_Event event;
		scope(exit) cleanup();      // when we exit, perform cleanup

		auto T=Clock();
		long delta;
		float max_fps=20;
		float interval=1/max_fps;
		long startTime,initialTime=T.now().ticks();
		float elapsed,elapsed_acc;
		int counter;
	
		mainLoop:
		while (true)
		{
			startTime=T.now().ticks();
			elapsed=0.1f;
			// handle all SDL events that we might've received in this loop iteration
			while (SDL_PollEvent(&event)) {
				switch (event.type) {
					// user has clicked on the window's close button
					case SDL_QUIT:
						break mainLoop;
						
					case SDL_KEYDOWN:
						auto evt=cast(SDL_KeyboardEvent)event;
						
						if (evt.keysym.sym==27) break mainLoop;
						
						if ((evt.keysym.sym==303)||(evt.keysym.sym==304)) shift=true;
						if ((evt.keysym.sym==305)||(evt.keysym.sym==306)) ctrl=true;
						if ((evt.keysym.sym==307)||(evt.keysym.sym==308)) alt=true;
						
						currentGS.on_key_press(evt.keysym.sym,shift,ctrl,alt);
						break;
					case SDL_KEYUP:
						auto evt=cast(SDL_KeyboardEvent)event;
						//logger.info(L("Button up key/state:{} / {}",evt.keysym.sym,evt.keysym.mod));
						if ((evt.keysym.sym==303)||(evt.keysym.sym==304)) shift=false;
						if ((evt.keysym.sym==305)||(evt.keysym.sym==306)) ctrl=false;
						if ((evt.keysym.sym==307)||(evt.keysym.sym==308)) alt=false;
						
						currentGS.on_key_release(evt.keysym.sym,shift,ctrl,alt);
						break;
					case SDL_MOUSEMOTION:
						auto evt=cast(SDL_MouseMotionEvent)event;
						
						currentGS.on_mouse_move(evt.x,size[1]-evt.y,evt.xrel,-evt.yrel,evt.state,shift,ctrl,alt);
						break;
					
					case SDL_MOUSEBUTTONDOWN:
						auto evt=cast(SDL_MouseButtonEvent)event;
						currentGS.on_mouse_press(evt.x,size[1]-evt.y,evt.button,shift,ctrl,alt);
						break;
					case SDL_MOUSEBUTTONUP:
						auto evt=cast(SDL_MouseButtonEvent)event;
						currentGS.on_mouse_release(evt.x,size[1]-evt.y,evt.button,shift,ctrl,alt);
						break;
					
					// by default, we do nothing => break from the switch
					default:
						break;
				}
			}
			
			
			// clear the screen. by default it clears to black
			glClear(GL_COLOR_BUFFER_BIT);
		
			// draw our stuff =)
			//logger.info("Avant draw");
			currentGS.step(interval);
			currentGS.draw(interval);
			//drawGLFrame();
			// swap the buffers, making our backbuffer the visible one
			SDL_GL_SwapBuffers();
			
			
			elapsed=(T.now().ticks()-startTime)*0.0000001;
			elapsed_acc+=elapsed;
			counter++;
			if (counter>1000)
			{
				Stdout.formatln("average t/frame (ms): {}",elapsed_acc/counter*10000f);
				elapsed_acc=0f;
				counter=0;
				
			}
			//if (interval-elapsed>0)
			//	Thread.sleep(interval-elapsed);
			
		}
    }
}

void main() {
	
	Logger logger = Log.getLogger("mylogger");
	logger.add(new AppendConsole());//"log.txt"));

	XenApp xen=new XenApp(logger);
    Stdout.formatln("TEST");
	xen.run();

}